负载均衡

推荐列表 站点导航

当前位置:首页 > 服务器技术 > 负载均衡 >

redis + 主从 + 持久化 + 分片 + 集群 + spring集成

来源:网络  作者:网友投稿  发布时间:2021-01-08 12:34
Redis是一个基于内存的数据库,其不仅读写速度快,每秒可以执行大约110000的写操作,81000的读取操作,而且其支持存...

Redis是一个基于内存的数据库,其不仅读写速度快,每秒可以执行大约110000的写操作,81000的读取操作,而且其支持存储字符串,哈希结构,链表,集合丰富的数据类型。所以得到很多开发者的青睐。加之其支持主从、持久化等功能,3.0版本开始正式提供分片技术、让其在大型互联网应用中大显身手,本文通过实际操作和理论相配合,对redis进行详细地阐述。

一、redis的安装与使用

下载直接去redis的官网进行不同操作系统对应的版本。本文中采用的redis的版本为3.2.5、linux平台,安装过程如下

[root@hbase usr]# tar -zxf redis-3.2.5.tar.gz [root@hbase usr]# cd redis-3.2.5 [root@hbase redis-3.2.5]# ll [root@hbase redis-3.2.5]# make [root@hbase redis-3.2.5]# cd src [root@hbase src]# ll

之后我们会发现其中redis-server和redis-cli,这两个文件分别对应启动redis的服务端和客户端,启动服务端

[root@hbase src]# ./redis-server 11579:M 13 Nov 15:07:01.399 # Warning: 32 bit instance detected but no memory limit set. Setting 3 GB maxmemory limit with 'noeviction' policy now. _._ _.-``__ ''-._ _.-`` `. `_. ''-._ Redis 3.2.5 (00000000/0) 32 bit .-`` .-```. ```/ _.,_ ''-._ ( ' , .-` | `, ) Running in standalone mode |`-._`-...-` __...-.``-._|'` _.-'| Port: 6379 | `-._ `._ / _.-' | PID: 11579 `-._ `-._ `-./ _.-' _.-' |`-._`-._ `-.__.-' _.-'_.-'| | `-._`-._ _.-'_.-' | `-._ `-._`-.__.-'_.-' _.-' |`-._`-._ `-.__.-' _.-'_.-'| | `-._`-._ _.-'_.-' | `-._ `-._`-.__.-'_.-' _.-' `-._ `-.__.-' _.-' `-._ _.-' `-.__.-' 11579:M 13 Nov 15:07:01.404 # Server started, Redis version 3.2.5 11579:M 13 Nov 15:07:01.409 * The server is now ready to accept connections on port 6379

可以看到,redis正常启动,6379 是 redis 服务端口,这个端口在redis.conf中可以进行配置,稍后我们讲解配置文件的时候会提到。不要关闭这个窗口,因为当前redis-server不是在后台运行,我们另起一个窗口,在当前目录下进行客户端连接服务端。

[hadoop@hbase src]$ ./redis-cli 127.0.0.1:6379>

说明一切正常,linux环境下的redis安装成功,至于windows下的安装过程相对更加简单,只需打开.exe文件即可,不在详细演示

二、redis数据类型

2.1 string

字符串类型是Redis中最为基础的数据存储类型,它在Redis中是二进制安全的,在Redis中字符串类型的Value最多可以容纳的数据长度是512M。除了get、set、作外,Redis还提供了其他的一些诸如追加、递增等功能。

set key value O(1) 设定该key对应的value,如果该Key已经存在,则覆盖其原有值。get key O(1) 获取指定Key的value,如果该Key不存在,返回nil。

setnx key value O(1) 如果指定的Key不存在,则设定该Key持有指定字符串value,此时其效果等价于set命令。如果该Key已经存在,该命令将不做任何操作。 

1 127.0.0.1:6379> set hello word 2 OK 3 127.0.0.1:6379> get hello 4 'word' 5 127.0.0.1:6379> set hello world 6 OK 7 127.0.0.1:6379> set hello world 8 OK 9 127.0.0.1:6379> get hello 10 'world' 11 127.0.0.1:6379> get world 12 (nil) 13 127.0.0.1:6379> set hello world_new 14 OK 15 127.0.0.1:6379> get hello 16 'world_new' 17 127.0.0.1:6379> setnx hello nihao 18 (integer) 0 19 127.0.0.1:6379> setnx new_hello nihao 20 (integer) 1

mset key value [key value ...] O(N) N表示指定Key的数量。该命令可以看成是多次迭代执行set命令。

mget key [key ...] O(N) N表示获取Key的数量。返回所有指定key的value,如果其中某个key不存在,该key的value将返回nil。 

msetnx key value [key value ...] O(N) N表示指定key的数量。该命令原子性的完成参数中所有key/value的设置操作,其具体行为可以看成是多次迭代执行setnx命令。如果在这一批keys中有任意一个key已经存在,那么该操作将全部回滚,即所有的修改都不会生效。 1表示所有keys都设置成功,0则表示没有任何key被修改。 

1 127.0.0.1:6379> mset key1 hello key2 world 2 OK 3 127.0.0.1:6379> mget key1 key2 4 1) 'hello' 5 2) 'world' 6 127.0.0.1:6379> mget key1 key3 7 1) 'hello' 8 2) (nil) 9 127.0.0.1:6379> msetnx key1 nihao key3 hi 10 (integer) 0 11 127.0.0.1:6379> msetnx key3 nihao key4 hi 12 (integer) 1

append key value  O(1) 若key已经存在,将value的数据追加到对应key的value的末尾。如果该key不存在,append命令将会创建一个新的key/value。

strlen key O(1) 返回指定Key的字符值长度,如果该Key不存在,返回0。

decr key O(1) 将指定key的value原子性的递减1。如果该key不存在,其初始值为0,在decr之后其值为-1。如果value的值不能转换为整型值,该操作将执行失败。

incr key O(1) 将指定key的value原子性的递增1。如果该Key不存在,其初始值为0,在incr之后其值为1。如果value的值不能转换为整型值,该操作将执行失败。 

decrby key decrement O(1) 将指定key的value原子性的减少decrement,其他同decr。

incrby key increment O(1) 将指定key的value原子性的增加increment,其他同incr。 

1 127.0.0.1:6379> append k1 hello 2 (integer) 5 3 127.0.0.1:6379> append k1 world 4 (integer) 10 5 127.0.0.1:6379> get k1 6 'helloworld' 7 127.0.0.1:6379> strlen k1 8 (integer) 10 9 127.0.0.1:6379> set k2 1 10 OK 11 127.0.0.1:6379> incr k2 12 (integer) 2 13 127.0.0.1:6379> get k2 14 '2' 15 127.0.0.1:6379> decr k2 16 (integer) 1 17 127.0.0.1:6379> get k2 18 '1' 19 127.0.0.1:6379> incrby k2 5 20 (integer) 6 21 127.0.0.1:6379> decrby k2 5 22 (integer) 1 23 127.0.0.1:6379> get k2 24 '1'

2.2 redis之数据类型list

在Redis中,List类型是按照插入顺序排序的字符串链表。和数据结构中的普通链表一样,我们可以在其头部(left)和尾部(right)添加新的元素,该操作也可以在常量时间内完成。在插入时,如果该键并不存在,Redis将为该键创建一个新的链表。与此相反,如果链表中所有的元素均被移除,那么该键也将会被从数据库中删除。List中可以包含的最大元素数量是4294967295。 

lpush key value [value ...] O(1) 在指定key所对应的List头部插入所有values。如果该Key不存在,则插入之前创建一个与该key关联的空链表。

lpop key O(1) 返回并弹出指定key对应链表的第一个元素。如果该Key不存在,返回nil。

lrange key start stop start和end都是0-len,即0表示链表头部的第一个元素。其中start的值也可以为负值,-1将表示链表中的最后一个元素,即尾部元素,-2表示倒数第二个并以此类推。该命令在获取元素时,start和end位置上的元素也会被取出。如果start的值大于链表中元素的数量,空链表将会被返回。如果end的值大于元素的数量,该命令则获取从start(包括start)开始,链表中剩余的所有元素。 

lpushx key value O(1) 当指定的key存在时,在其所关联的list的头部插入参数中给出的value,否则将不会有任何操作发生。    

lrem key count value O(N) 在指定key关联的链表中,删除前count个值等于value的元素。如果count大于0,从头向尾遍历并删除,如果count小于0,则从尾向头遍历并删除。如果count等于0,则删除链表中所有等于value的元素。如果指定的key不存在,则直接返回0。

llen key O(1) 返回指定key关联的链表中元素的数量,如果该Key不存在,则返回0。。

lset  key index value O(N) 设定链表中指定位置的值为新值,其中0表示第一个元素,即头部元素,-1表示尾部元素。 

1 127.0.0.1:6379> lpush k1 v1 v2 v3 2 (integer) 3 3 127.0.0.1:6379> lrange k1 0 2 4 1) 'v3' 2) 'v2' 3) 'v1' 5 127.0.0.1:6379> lpop k1 6 'v3' 7 127.0.0.1:6379> lrange k1 0 2 8 1) 'v2' 2) 'v1' 9 127.0.0.1:6379> lpush k1 v4 10 (integer) 3 11 127.0.0.1:6379> lrange k1 0 2 12 1) 'v4' 2) 'v2' 3) 'v1' 13 127.0.0.1:6379> lpush k1 v4 14 (integer) 4 15 127.0.0.1:6379> lpush k1 v4 16 (integer) 5 17 127.0.0.1:6379> lpush k1 v4 18 (integer) 6 19 127.0.0.1:6379> lrange k1 0 5 20 1) 'v4' 2) 'v4' 3) 'v4' 4) 'v4' 5) 'v2' 6) 'v1' 21 127.0.0.1:6379> lrem k1 2 v4 # 删除前两个值为v4的元素 22 (integer) 2 23 127.0.0.1:6379> lrange k1 0 3 24 1) 'v4' 2) 'v4' 3) 'v2' 4) 'v1' 25 127.0.0.1:6379> llen k1 26 (integer) 4 27 127.0.0.1:6379> lset k1 1 k5 #设置索引为1的值为k5 28 OK 29 127.0.0.1:6379> lrange k1 0 3 30 1) 'v4' 2) 'k5' 3) 'v2' 4) 'v1'

rpush key value [value ...] O(1) 在指定key所对应的List尾部插入所有values。如果该Key不存在,则插入之前创建一个与该key关联的空链表。

rpop key O(1) 返回并弹出指定key对应链表的最后一个元素。如果该Key不存在,返回nil。

rpushx key value O(1) 当指定的key存在时,在其所关联的list的尾部插入参数中给出的value,否则将不会有任何操作发生。  

1 127.0.0.1:6379> lrange k1 0 3 2 1) 'v4' 2) 'k5' 3) 'v2' 4) 'v1' 3 127.0.0.1:6379> rpushx k1 k6 4 (integer) 5 5 127.0.0.1:6379> lrange k1 0 4 6 1) 'v4' 2) 'k5' 3) 'v2' 4) 'v1' 5) 'k6' 7 127.0.0.1:6379> rpush k1 k7 k8 #在尾部添加元素 8 (integer) 7 9 127.0.0.1:6379> lrange k1 0 6 10 1) 'v4' 2) 'k5' 3) 'v2' 4) 'v1' 5) 'k6' 6) 'k7' 7) 'k8' 11 127.0.0.1:6379> rpop k1 #弹出尾部的元素 12 'k8' 13 127.0.0.1:6379> lrange k1 0 5 14 1) 'v4' 2) 'k5' 3) 'v2' 4) 'v1' 5) 'k6' 6) 'k7' 15 127.0.0.1:6379>

2.3 hash

Redis hash 是一个string类型的field和value的映射表,hash特别适合用于存储对象。每一个Hash可以存储4294967295个键值对。

hset key field value O(1) 为指定的key设置field/value对,若key不存在,则创建新key,并创建field/value对,若该key中已经存在,则用新值覆盖其原有值。

hget key field O(1) 返回指定key中指定field所对应的值,若key或field不存在,返回nil。

hmget key field [field ...] O(N) 获取指定fields关联的一组values。如果请求的field不存在,其值返回nil。

hmset key field value [field value ...] O(N) 逐个依次设置参数中给出的field/value对。如果其中某个field已经存在,则用新值覆盖原有值。如果key不存在,则创建新key,同时设定参数中的field/value。

hsetnx key field value O(1) 只有当key或field不存在时,为指定的key设定field/value对,否则该命令不会进行任何操作。

1 127.0.0.1:6379> hset k1 f1 v1 2 (integer) 1 3 127.0.0.1:6379> hset k1 f2 v2 4 (integer) 1 5 127.0.0.1:6379> hget k1 f1 6 'v1' 7 127.0.0.1:6379> hmget k1 f1 f2 8 1) 'v1' 2) 'v2' 9 127.0.0.1:6379> hmset k1 f3 v3 f4 v4 10 OK 11 127.0.0.1:6379> hmget k1 f1 f2 f3 f4 12 1) 'v1' 2) 'v2' 3) 'v3' 4) 'v4' 13 127.0.0.1:6379> hsetnx k1 f1 v5 14 (integer) 0 15 127.0.0.1:6379> hsetnx k1 f5 v5 16 (integer) 1 17 127.0.0.1:6379> hmget k1 f1 f2 f3 f4 f5 18 1) 'v1' 2) 'v2' 3) 'v3' 4) 'v4' 5) 'v5'

hkeys key O(N) 返回指定key的所有fields名。

hvals key O(N) 返回指定Key的所有values名。

hexists key field O(1) 判断指定key中的指定field是否存在。1表示存在,0表示field或key不存在。

hlen key O(1) 获取该key所包含的field的数量。返回key包含的field数量,如果key不存在,返回0。

hdel key field [field ...] O(N) 从指定key的hash中删除指定的多个字段,如果不存在的字段将被忽略。

hincrby key field increment O(1) 增加指定key中指定field对应的value的值。如果key或field不存在,该命令将会创建一个新key或新field。 

1 127.0.0.1:6379> hkeys k1 2 1) 'f1' 2) 'f2' 3) 'f3' 4) 'f4' 5) 'f5' 3 127.0.0.1:6379> hvals k1 4 1) 'v1' 2) 'v2' 3) 'v3' 4) 'v4' 5) 'v5' 5 127.0.0.1:6379> hexists k1 f1 6 (integer) 1 7 127.0.0.1:6379> hlen k1 8 (integer) 5 9 127.0.0.1:6379> hdel k1 f5 10 (integer) 1 11 127.0.0.1:6379> hset k1 f5 1 12 (integer) 1 13 127.0.0.1:6379> hvals k1 14 1) 'v1' 2) 'v2' 3) 'v3' 4) 'v4' 5) '1' 15 127.0.0.1:6379> hincrby k1 f5 2 16 (integer) 3 17 127.0.0.1:6379> hvals k1 18 1) 'v1' 2) 'v2' 3) 'v3' 4) 'v4' 5) '3'

2.4 set

在Redis中, Set类型看作为没有排序的字符集合,和List类型一样,我们也可以在该类型的数据值上执行添加、删除或判断某一元素是否存在等操作。set可包含的最大元素数量是4294967295。set集合中不允许出现重复的元素。 

sadd key member [member ...] O(N) 若该Key不存在,该命令将会创建一个新的set。若有的成员在set中已经存在,该成员将被忽略,而其它成员仍将会被正常插入。

spop key O(1) 随机的移除并返回set中的某一成员。

scard key O(1) 获取set中成员的数量。

sismember key member O(1) 判断参数中指定成员是否已经存在于与key所在的set集合中。

smembers key O(N) 获取与该key关联的set中所有的成员。     

srem key member [member ...] O(N) 从与key关联的set中删除参数中指定的成员,不存在的参数成员将被忽略。

1 127.0.0.1:6379> sadd k1 m1 2 (integer) 1 3 127.0.0.1:6379> sadd k1 m2 4 (integer) 1 5 127.0.0.1:6379> scard k1 6 (integer) 2 7 127.0.0.1:6379> spop k1 8 'm2' 9 127.0.0.1:6379> sadd k1 m3 10 (integer) 1 11 127.0.0.1:6379> sismember k1 m3 12 (integer) 1 13 127.0.0.1:6379> smembers k1 14 1) 'm3' 15 2) 'm1' 16 127.0.0.1:6379> srem k1 m1 17 (integer) 1 18 127.0.0.1:6379> smembers k1 19 1) 'm3'

sdiff key [key ...] O(N) 返回第一个key所关联的set和其后所有keys所关联的sets中成员的差异。

sinter  key [key ...] O(N*M) 返回参数中所有keys关联的sets中成员的交集。

sunion key [key ...] O(N) 返回参数中所有keys关联的sets中成员的并集。  

127.0.0.1:6379> smembers k1 1) 'm2' 2) 'm1' 3) 'm3' 127.0.0.1:6379> smembers k2 1) 'm3' 2) 'm1' 3) 'm4' 127.0.0.1:6379> sdiff k1 k2 1) 'm2' 127.0.0.1:6379> sinter k1 k2 1) 'm1' 2) 'm3' 127.0.0.1:6379> sunion k1 k2 1) 'm3' 2) 'm1' 3) 'm2' 4) 'm4'

2.5 sorted set

sorted-set和set类型极为相似,都不允许重复的成员出现在一个Set中。它们之间的主要差别是sorted-set中的每一个成员都会有一个分数(score)与之关联,Redis正是通过分数来为集合中的成员进行从小到大的排序。

zadd key score member [score] [member] O(log(N)) 添加参数中指定的所有成员及其分数到指定key的sorted-sett中。

zcard key O(1) 获取与该key相关联的sorted-set中包含的成员数量。

zscore key member O(1) 获取指定Key的指定成员的分数。如果该成员存在,以字符串的形式返回其分数,否则返回nil。

zcount key min max O(log(N)+M) 用于获取分数(score)在min和max之间的成员数量。min和max表示的范围是闭区间范围,即min <= score <= max内的成员将被返回。

zincrby key increment member O(log(N)) 将为指定Key中的指定成员增加指定的分数。

zrange key start stop [WITHSCORES] O(log(N)+M)  返回顺序在start和stop指定范围内的成员列表。

zrangebyscore key min max [WITHSCORES] [LIMIT offset count] O(log(N)+M) 将返回分数在min和max之间的所有成员列表。

zrem key member [member ...] O(M log(N)) 移除参数中指定的成员,其中不存在的成员将被忽略。

zremrangebyscore key min max O(log(N)+M) 删除分数在min和max之间的所有成员,即满足表达式min <= score <= max的所有成员。 

1 127.0.0.1:6379> zadd k1 1 m1 2 (integer) 1 3 127.0.0.1:6379> zadd k1 2 m2 4 (integer) 1 5 127.0.0.1:6379> zadd k1 3 m3 6 (integer) 1 7 127.0.0.1:6379> zcard k1 8 (integer) 3 9 127.0.0.1:6379> zscore k1 m1 10 '1' 11 127.0.0.1:6379> zscore k1 m2 12 '2' 13 127.0.0.1:6379> zcount k1 2 3 14 (integer) 2 15 127.0.0.1:6379> zincrby k1 3 m3 16 '6' 17 127.0.0.1:6379> zrange k1 1 10 18 1) 'm2' 19 2) 'm3' 20 127.0.0.1:6379> zrange k1 0 10 21 1) 'm1' 22 2) 'm2' 23 3) 'm3' 24 127.0.0.1:6379> zcount k1 0 10 25 (integer) 3 26 127.0.0.1:6379> zrangebyscore k1 0 6 27 1) 'm1' 28 2) 'm2' 29 3) 'm3' 30 127.0.0.1:6379> zrem k1 m1 31 (integer) 1 32 127.0.0.1:6379> zcard k1 33 (integer) 2 34 127.0.0.1:6379> zremrangebyscore k1 2 3 35 (integer) 1 36 127.0.0.1:6379> zremrangebyscore k1 2 10 37 (integer) 1 38 127.0.0.1:6379> zcard k1 39 (integer) 0

三、redis的相关命令 

keys pattern O(N) 获取所有匹配pattern参数的Keys。需要说明的是,在我们的正常操作中应该尽量避免对该命令的调用,因为对于大型数据库而言,该命令是非常耗时的。pattern支持glob-style的通配符格式,如*表示任意一个或多个字符,?表示任意字符,[abc]表示方括号中任意一个字母。
del key [key ...] O(N) 从数据库删除中参数中指定的keys,如果指定键不存在,则直接忽略。
exists key O(1) 判断指定键是否存在。 1表示存在,0表示不存在。
move key db O(1) 将当前数据库中指定的键key移动到参数中指定的数据库中。若该key在目标数据库中已经存在,或者在当前数据库中不存在,该命令将不做任何操作并返回0。 移动成功返回1,否则0。
rename key newkey O(1) 为指定指定的键重新命名,如果两个keys的命令相同,或者是源key不存在,该命令都会返回相关的错误信息。如果newKey已经存在,则直接覆盖。
renamenx key newkey O(1) 如果新值不存在,则将参数中的原值修改为新值。其它条件和rename一致。1表示修改成功,否则0。
expire key seconds O(1) 该命令为指定的key设定超时的秒数,在超过该时间后,key被自动的删除。如果该Key在超时之前被修改,与该键关联的超时将被移除。1表示超时被设置,0则表示Key不存在,或不能被设置。
expireat key timestamp O(1) 该命令的逻辑功能和expire完全相同,差别是该命令指定的超时时间是绝对时间,而不是相对时间。该时间参数是Unix timestamp格式的,即从1970年1月1日开始所流经的秒数。1表示超时被设置,0则表示Key不存在,或不能被设置。
ttl key O(1) 获取该键所剩的超时描述。如果该键不存在或没有超时设置,则返回-1。
type key O(1) 获取与参数中指定键关联值的类型,该命令将以字符串的格式返回。 返回的字符串为string、list、set、hash和zset,如果key不存在返回none。

1 127.0.0.1:6379> keys * 2 (empty list or set) 3 127.0.0.1:6379> set str string 4 OK 5 127.0.0.1:6379> hset hash3 f1 v1 6 (integer) 1 7 127.0.0.1:6379> sadd set1 v1 8 (integer) 1 9 127.0.0.1:6379> zadd sortedset1 1 v1 10 (integer) 1 11 127.0.0.1:6379> lpush list1 v1 v2 12 (integer) 2 13 127.0.0.1:6379> keys * 14 1) 'hash3' 15 2) 'sortedset1' 16 3) 'list1' 17 4) 'str' 18 5) 'set1' 19 127.0.0.1:6379> keys s* 20 1) 'sortedset1' 21 2) 'str' 22 3) 'set1' 23 127.0.0.1:6379> exists list1 24 (integer) 1 25 127.0.0.1:6379> rename list1 list2 26 OK 27 127.0.0.1:6379> keys * 28 1) 'hash3' 29 2) 'sortedset1' 30 3) 'str' 31 4) 'list2' 32 5) 'set1' 33 127.0.0.1:6379> type list2 34 list 35 127.0.0.1:6379> type str 36 string 37 127.0.0.1:6379> set str2 v2 38 OK 39 127.0.0.1:6379> expire str2 10 40 (integer) 1 41 127.0.0.1:6379> ttl str2 42 (integer) 6 43 127.0.0.1:6379> ttl str2 44 (integer) -2 45 127.0.0.1:6379> keys * 46 1) 'hash3' 47 2) 'sortedset1' 48 3) 'str' 49 4) 'list2' 50 5) 'set1' 51 127.0.0.1:6379> move str 1 52 (integer) 1 53 127.0.0.1:6379> keys * 54 1) 'hash3' 55 2) 'sortedset1' 56 3) 'list2' 57 4) 'set1' 58 127.0.0.1:6379> select 1 59 OK 60 127.0.0.1:6379[1]> keys * 61 1) 'str' 62 127.0.0.1:6379[1]> select 0 63 OK 64 127.0.0.1:6379> del set1 65 (integer) 1 66 127.0.0.1:6379> keys * 67 1) 'hash3' 68 2) 'sortedset1' 69 3) 'list2'

四、redis的事务

1). 所有命令顺序执行,期间,Redis不会再为其它客户端的请求提供任何服务,从而保证了事物中的所有命令被原子的执行。
2). 和关系型数据库中的事务不同的是,在Redis事务中如果有某一条命令执行失败,其后的命令仍然会被继续执行。
3). 我们可以通过MULTI命令开启一个事务,有关系型数据库开发经验的人可以将其理解为'BEGIN TRANSACTION'语句。在该语句之后执行的命令都将被视为事务之内的操作,最后我们可以通过执行EXEC/DISCARD命令来提交/回滚该事务内的所有操作。这两个Redis命令可被视为等同于关系型数据库中的COMMIT/ROLLBACK语句。

multi 用于标记事务的开始,其后执行的命令都将被存入命令队列,直到执行exec时,这些命令才会被原子的执行。 始终返回OK
exec 执行在一个事务内命令队列中的所有命令,同时将当前连接的状态恢复为正常状态,即非事务状态。如果在事务中执行了watch命令,那么只有当watch所监控的keys没有被修改的前提下,exec命令才能执行事务队列中的所有命令,否则exec将放弃当前事务中的所有命令。 原子性的返回事务中各条命令的返回结果。如果在事务中使用了watch,一旦事务被放弃,exec将返回NULL-multi-bulk回复。

1 127.0.0.1:6379> multi 2 OK 3 127.0.0.1:6379> set k1 string 4 QUEUED 5 #由于k1为字符串类型,所以incr会报错,但是以后其他命令正常执行 6 127.0.0.1:6379> incr k1 7 QUEUED 8 127.0.0.1:6379> set k1 newstring 9 QUEUED 10 127.0.0.1:6379> get k1 11 QUEUED 12 127.0.0.1:6379> exec 13 1) OK 14 2) (error) ERR value is not an integer or out of range 15 3) OK 16 4) 'newstring'

discard 回滚事务队列中的所有命令,同时再将当前连接的状态恢复为正常状态,即非事务状态。如果watch命令被使用,该命令将unwatch所有的Keys。
watch key [key ...] O(1) 在multi命令执行之前,可以指定待监控的keys,然而在执行exec之前,如果被监控的keys发生修改,exec将放弃执行该事务队列中的所有命令。
unwatch O(1) 取消当前事务中指定监控的keys,如果执行了exec或discard命令,则无需手工执行该命令,因为事务中所有被监控的keys都将自动取消。 

1 127.0.0.1:6379> set id 1 2 OK 3 127.0.0.1:6379> set name n1 4 OK 5 127.0.0.1:6379> set age 12 6 OK 7 127.0.0.1:6379> watch id 8 OK 9 127.0.0.1:6379> multi 10 OK 11 127.0.0.1:6379> set name n2 12 QUEUED 13 127.0.0.1:6379> incr age 14 QUEUED 15 127.0.0.1:6379> exec 16 (nil) 17 127.0.0.1:6379> get age 18 '12' 19 127.0.0.1:6379> get name 20 'n1'

注意,在提交事务之前,则执行exec命令之前,我们在另一个窗口对id进行修改(set id 2),可以看出,该事务没有执行成功

五、redis的主从复制

1). 同一个Master可以同步多个Slaves节点。

2). Slave同样可以接受其它Slaves的连接和同步请求。

3). Master Server是以非阻塞的方式为Slaves提供服务。所以在Master-Slave同步期间,客户端仍然可以提交查询或修改请求。

4). Slave Server同样是以非阻塞的方式完成数据同步。在同步期间,如果有客户端提交查询请求,Redis则返回同步之前的数据。

5). 为了分载Master的读操作压力,Slave服务器可以为客户端提供只读操作的服务,写服务仍然必须由Master来完成。从而实现读写分离

在Slave启动并连接到Master之后,它将主动发送一个SYNC命令。此后Master将启动后台存盘进程,同时收集所有接收到的用于修改数据集的命令,在后台进程执行完毕后,Master将传送整个数据库文件到Slave,以完成一次完全同步。而Slave服务器在接收到数据库文件数据之后将其存盘并加载到内存中。此后,Master继续将所有已经收集到的修改命令,和新的修改命令依次传送给Slaves,Slave将在本次执行这些数据修改命令,从而达到最终的数据同步。若Master和Slave之间的链接出现断连现象,Slave可以自动重连Master,但是在连接成功之后,一次完全同步将被自动执行。 

同时启动两个Redis服务器,可以考虑在同一台机器上启动两个Redis服务器,分别监听不同的端口,如6379和6380。复制redis.conf并命名为slave.conf,编辑该配置文件,在84行位置将其中监听的端口改为6380:配置如下port 6380,分配启动两个server,启动时可以将配置文件作为启动命令的参数。命令如下:redis-server redis.conf ,当我们把两个server都启动时,可以进行以下步骤:

1 redis-cli -p 6380

通过不同的端口来链接服务端,此时,当前客户端链接的6380端口的服务端,我们让这个服务端当做slave节点的角色。执行如下命令

slaveof 127.0.0.1 6379

当返回ok时,这里我Master-Slave建立成功。在监听端口为6379的服务器上我们用客户端进行操作

1 [root@hbase redis-3.2.5]# src/redis-cli -p 6379 2 127.0.0.1:6379> set k1 v1 3 OK 4 127.0.0.1:6379> hset k2 f2 v2 5 (integer) 1 6 127.0.0.1:6379>

在slave节点,获取该值:

1 [root@hbase redis-3.2.5]# src/redis-cli -p 6380 2 127.0.0.1:6380> slaveof 127.0.0.1 6379 3 OK 4 127.0.0.1:6380> keys * 5 1) 'k1' 6 2) 'k2' 7 127.0.0.1:6380> get k1 8 'v1'

说明两个节点主从已经同步。实现了主从同步的效果。需要注意的是:上面的方式只是保证了在执行slaveof命令之后,redis_6380成为了redis_6379的slave,一旦服务(redis_6380)重新启动之后,他们之间的复制关系将终止。如果希望长期保证这两个服务器之间的Replication关系,可以在redis_6380的配置文件中做如下修改:

# slaveof <masterip> <masterport>改为slaveof 127.0.0.1 6379

保存退出。这样就可以保证Redis_6380服务程序在每次启动后都会主动建立与Redis_6379的Replication连接了。

六、redis的持久化

6.1、Redis提供的持久化机制: 

1). RDB持久化:该机制是指在指定的时间间隔内将内存中的数据集快照写入磁盘。 

2). AOF持久化:该机制将以日志的形式记录服务器所处理的每一个写操作,在Redis服务器启动之初会读取该文件来重新构建数据库,以保证启动后数据库中的数据是完整的。

6.2、RDB机制的优势和劣势:

优势:
1). 采用该方式,整个Redis数据库将只包含一个文件,通过这样的备份策略,一旦系统出现灾难性故障,我们可以非常容易的进行恢复。
2). 性能最大化,对于Redis的服务进程而言,在开始持久化时,它唯一需要做的只是fork出子进程,再由子进程完成这些持久化的工作,这样可以极避免服务进程执行IO操作。
劣势:

1). 如果你想保证数据的高可用性,那么RDB将不是一个很好的选择。因为系统一旦在定时持久化之前出现宕机现象,此前没有来得及写入磁盘的数据都将丢失。

2). 由于RDB是通过fork子进程来协助完成数据持久化工作的,因此,如果当数据集较大时,可能会导致整个服务器停止服务一定的时间。

6.3、AOF机制的优势和劣势: 

优势
1). 带来更高的数据安全性,即数据持久性。Redis中提供了3中同步策略,即每秒同步、每修改同步和不同步。事实上,每秒同步也是异步完成的,其效率也是非常高的,所差的是一旦系统出现宕机现象,那么这一秒钟之内修改的数据将会丢失。而每修改同步,我们可以将其视为同步持久化,即每次发生的数据变化都会被立即记录到磁盘中。可以预见,这种方式在效率上是最低的。

2). 由于该机制对日志文件的写入操作采用的是append模式,因此在写入过程中即使出现宕机现象,也不会破坏日志文件中已经存在的内容。然而如果我们本次操作只是写入了一半数据就出现了系统崩溃问题,在Redis下一次启动之前,可以通过redis-check-aof工具来解决数据一致性的问题。

3). 如果日志过大,Redis可以自动启用rewrite机制。即Redis以append模式不断的将修改数据写入到老的磁盘文件中,同时Redis还会创建一个新的文件用于记录此期间有哪些修改命令被执行。因此在进行rewrite切换时可以更好的保证数据安全性。

4). AOF包含一个格式清晰、易于理解的日志文件用于记录所有的修改操作。事实上,我们也可以通过该文件完成数据的重建。
劣势
1). 对于相同数量的数据集而言,AOF文件通常要大于RDB文件。
2). 根据同步策略的不同,AOF在运行效率上往往会慢于RDB。

介绍完理论之后,我们配置redis的持久化方案:

rdb方案,在redis.conf中如下配置(默认配置) 

1 save 900 1 #在900秒(15分钟)之后,如果至少有1个key发生变化,则dump内存快照。 2 save 300 10 #在300秒(5分钟)之后,如果至少有10个key发生变化,则dump内存快照。 3 save 60 10000 #在60秒(1分钟)之后,如果至少有10000个key发生变化,则dump内存快照。

aof方案的配置:

1 在Redis的配置文件中存在三种同步方式,它们分别是: 2 appendfsync always #每次有数据修改发生时都会写入AOF文件。 3 appendfsync everysec #每秒钟同步一次,该策略为AOF的缺省策略。 4 appendfsync no #从不同步。高效但是数据不会被持久化。

七、redis的分片

分片(partitioning)就是将你的数据拆分到多个 Redis 实例的过程,Redis 引入另一种哈希槽(hash slot)的概念。Redis 集群中内置了 16384 个哈希槽,当需要在 Redis 集群中放置一个 key-value 时,redis 先对 key 使用 crc16 算法得出结果,然后对 16384 求余数,这样每个 key 对应一个编号在 0-16383 之间的哈希槽,redis 会根据节点数量大致均等的将哈希槽映射到不同节点。

原来的redis分片实现:

客户端分片(Client side partitioning),客户端直接选择正确的节点来写入和读取指定键。

代理协助分片(Proxy assisted partitioning),客户端发送请求到一个可以理解 Redis 协议的代理上,而不是直接发送请求到 Redis 实例上。代理会根据配置好的分片模式,来保证转发请求到正确的 Redis 实例,并返回响应给客户端。

查询路由(Query routing),发送查询到一个随机实例,这个实例会保证转发查询到正确的节点。 

新版本Redis的解决办法:

Redis3.0版的一大特性就是支持集群(Cluster)功能。Redis集群是自动分片和高可用的首选方式。集群的特点在于拥有和单机实例同样的功能,同时在网络分区后能够提供一定的可访问性以及对主数据库故障恢复的支持。

搭建redis集群环境需要执行的ruby的脚本,所以需要安装ruby的环境。建议用yum进行安装,由于具体的操作环境不相同,所以具体操作过程还需视操作环境而定 

1 [root@root java]# yum install ruby 2 [root@root java]# yum install rubygems 3 [root@root java]# gem install redis

期间会出现选择选项,键入yes即可。当出现Successfully installed redis-3.3.1  1 gem installed,说明redis集群需要的ruby环境安装成功。开始搭建redis环境

创建redis-cluster文件夹,并在其中创建6379,6380,6381文件夹,修改redis.conf文件,并将其中的端口分别设置成6379,6380,6381,redis.conf中的其他配置为

daemonize yes

cluster-enabled yes

cluster-config-file nodes.conf

cluster-node-timeout 5000

appendonly yes

结构目录如下:

1 [root@storm1 java]# cd redis-cluster/ 2 [root@storm1 redis-cluster]# ll 3 total 12 4 drwxr-xr-x. 2 root root 4096 Nov 14 05:50 6379 5 drwxr-xr-x. 2 root root 4096 Nov 14 05:51 6380 6 drwxr-xr-x. 2 root root 4096 Nov 14 05:52 6381 7 [root@storm1 redis-cluster]# cd 6379 8 [root@storm1 6379]# cat redis.conf 9 port 6379 10 daemonize yes 11 cluster-enabled yes 12 cluster-config-file nodes.conf 13 cluster-node-timeout 5000 14 appendonly yes[root@storm1 6379]# more ../6380/redis.conf 15 port 6380 16 daemonize yes 17 cluster-enabled yes 18 cluster-config-file nodes.conf 19 cluster-node-timeout 5000 20 appendonly yes 21 [root@storm1 6379]#

分别启动这3个redis实例,并创建集群,让三个实例互相通讯:

1 [root@storm1 redis-3.2.5]# src/redis-trib.rb create --replicas 0 127.0.0.1:6379 127.0.0.1:6380 127.0.0.1:6381 2 >>> Creating cluster 3 >>> Performing hash slots allocation on 3 nodes... 4 Using 3 masters: 5 127.0.0.1:6379 6 127.0.0.1:6380 7 127.0.0.1:6381 8 M: 76d37cdb954e0c293cec5c6bc27015af40d4a59f 127.0.0.1:6379 9 slots:0-5460 (5461 slots) master 10 M: f18ab812b7f9e933639b3afdab964039ddd3ceba 127.0.0.1:6380 11 slots:5461-10922 (5462 slots) master 12 M: 644f9bca1af9cc9e3f1543ab5f0b434d11ff59b0 127.0.0.1:6381 13 slots:10923-16383 (5461 slots) master 14 Can I set the above configuration? (type 'yes' to accept): yes 15 >>> Nodes configuration updated 16 >>> Assign a different config epoch to each node 17 >>> Sending CLUSTER MEET messages to join the cluster 18 Waiting for the cluster to join.... 19 >>> Performing Cluster Check (using node 127.0.0.1:6379) 20 M: 76d37cdb954e0c293cec5c6bc27015af40d4a59f 127.0.0.1:6379 21 slots:0-5460 (5461 slots) master 22 0 additional replica(s) 23 M: 644f9bca1af9cc9e3f1543ab5f0b434d11ff59b0 127.0.0.1:6381 24 slots:10923-16383 (5461 slots) master 25 0 additional replica(s) 26 M: f18ab812b7f9e933639b3afdab964039ddd3ceba 127.0.0.1:6380 27 slots:5461-10922 (5462 slots) master 28 0 additional replica(s) 29 [OK] All nodes agree about slots configuration. 30 >>> Check for open slots... 31 >>> Check slots coverage... 32 [OK] All 16384 slots covered.

至此redis集群即搭建成功,简单进行测试一下

1 [root@storm1 redis-3.2.5]# src/redis-cli -c -p 6379 2 127.0.0.1:6379> set k1 v1 3 -> Redirected to slot [12706] located at 127.0.0.1:6381 4 OK 5 127.0.0.1:6381> exit 6 [root@storm1 redis-3.2.5]# src/redis-cli -c -p 6381 7 127.0.0.1:6381> keys * 8 1) 'k1' 9 127.0.0.1:6381>

可以看到,虽然我们第一次连接的是6379端口,redis cluster 自动帮我们重定向到 6381 。在6381端口的实例中出现了我们之前设置的k1,说明整个集群是工作的。

八、redis的管理命令

config get parameter 用于读取服务器的运行时参数,但是并不是所有的配置参数都可以通过该命令进行读取。该命令的参数接受glob风格的模式匹配规则,因此如果参数中包含模式元字符,那么所有匹配的参数都将以key/value方式被列出。如果参数是*,那么该命令支持的所有参数都将被列出。

config set parameter value 该命令用于配置Redis服务器的运行时参数,在设置成功之后无需重启便可生效。然而并非所有的参数都可以通过该命令进行动态设置。
dbsize 返回当前打开的数据库中keys的数量。
flushall  清空当前服务器管理的数据库中的所有keys,不仅限于当前打开的数据库。
flushdb  清空当前数据库中的所有keys。
info  获取和服务器运行状况相关的一些列统计数字。
save 设置RDB持久化模式的保存策略。
shutdown  停止所有的客户端,同时以阻塞的方式执行内存数据持久化。如果AOF模式被启用,则将缓存中的数据flush到AOF文件。退出服务器。
slaveof host port 该命令用于修改slave服务器的主从复制设置。
slowlog subcommand [argument] 该命令主要用于读取执行时间较长的命令。由于slowlog队列不会被持久化到磁盘,因此Redis在收集命令时不会对性能产生很大的影响。通常我们可以将参数'slowlog-log-slower-than'设置为0,以便收集所有命令的执行时间。该命令还包含以下几个子命令:
1). slowlog get N: 从slowlog队列中读取命令信息,N表示最近N条命令的信息。
2). slowlog len:获取slowlog队列的长度。
3). slowlog reset:清空slowlog中的内容。

1 redis 127.0.0.1:6379> config get port 2 1) 'port' 3 2) '6379' 4 redis 127.0.0.1:6379> keys * 5 1) 'k1' 6 redis 127.0.0.1:6379> flushdb 7 OK 8 redis 127.0.0.1:6379> keys * 9 (empty list or set) 10 redis 127.0.0.1:6379> dbsize 11 (integer) 0 12 redis 127.0.0.1:6379> set k1 v1 13 OK 14 redis 127.0.0.1:6379> dbsize 15 (integer) 1

九、redis的java操作

maven依赖 

1 <dependency> 2 <groupId>redis.clients</groupId> 3 <artifactId>jedis</artifactId> 4 <version>2.6.2</version> 5 <type>jar</type> 6 <scope>compile</scope> 7 </dependency>

java代码:

1 import redis.clients.jedis.Jedis; 2 3 public class RedisDao { 4 5 public static void main(String[] args) { 6 Jedis jedis = new Jedis('127.0.0.1', 6379); 7 jedis.set('k2', 'v2'); 8 System.out.println(jedis.get('k2')); 9 jedis.hset('k3', 'f1', 'v1'); 10 System.out.println(jedis.hget('k3', 'f1')); 11 System.out.println(jedis.keys('*')); 12 jedis.close(); 13 } 14 }

十、redis与spring整合 

10.1 引入jedis包和spring包

10.2 spring-mvc.xml 

1 <?xml version='1.0' encoding='UTF-8'?> 2 <beans xmlns='' xmlns:xsi='' xmlns:context='' xsi:schemaLocation=' http://www.springframework.org/schema/beans/spring-beans.xsd 3 http://www.springframework.org/schema/context/spring-context.xsd' default-autowire='byName'> 4 5 <bean id='redisClient' class='com.eztcn.commons.redis.RedisClientFactoryBean'> 6 <!-- 单个应用中的链接池最大链接数,默认8 --> 7 <property name='maxTotal' value='150' /> 8 <!-- 单个应用中的链接池最大空闲数,默认8 --> 9 <property name='maxIdle' value='50' /> 10 <!-- 单个应用中的链接池最大链接数,默认8 --> 11 <property name='minIdle' value='30' /> 12 <!-- 设置在每一次取对象时测试ping --> 13 <property name='testOnBorrow' value='false' /> 14 <!-- host:port --> 15 <property name='ipConfString' value='192.168.1.60:7001' /> 16 </bean> 17 </beans>

当然需要在spring配置文件中引入该配置文件:<import resource='spring/spring-config-redis.xml' />

10.3 RedisClientFactoryBean.java 

1 package com.commons.redis; 2 3 import org.apache.commons.lang3.StringUtils; 4 import org.springframework.beans.factory.FactoryBean; 5 6 public class RedisClientFactoryBean implements FactoryBean<RedisClient> { 7 private RedisClientConfig redisClientConfig = new RedisClientConfig(); 8 9 public RedisClient getObject() throws Exception { 10 if (StringUtils.isNotBlank(this.redisClientConfig.getIpConfString())) { 11 return new RedisClient(this.redisClientConfig); 12 } 13 throw new RedisInitializerException('RedisClient init parameter masterConfString is empty,please check spring config file!'); 14 } 15 16 public Class<?> getObjectType() { 17 return RedisClient.class; 18 } 19 20 public boolean isSingleton() { 21 return true; 22 } 23 24 public void setIpConfString(String string) { 25 this.redisClientConfig.setIpConfString(string); 26 } 27 28 public void setMaxTotal(int maxTotal) { 29 this.redisClientConfig.setMaxTotal(maxTotal); 30 } 31 32 public void setMaxIdle(int maxIdle) { 33 this.redisClientConfig.setMaxIdle(maxIdle); 34 } 35 36 public void setMinIdle(int minIdle) { 37 this.redisClientConfig.setMinIdle(minIdle); 38 } 39 40 public void setTestOnBorrow(boolean flag) { 41 this.redisClientConfig.setTestOnBorrow(flag); 42 } 43 }

10.4 RedisClientConfig.java

1 package com.commons.redis; 2 3 import org.apache.commons.pool2.impl.GenericObjectPoolConfig; 4 5 /** 6 * 7 * @描述 : 配置redis的相关属性 8 * @创建时间: 2015年7月20日上午11:05:53 9 * 10 */ 11 public class RedisClientConfig { 12 private GenericObjectPoolConfig jedisPoolConfig = new GenericObjectPoolConfig(); 13 14 private String ipConfString; 15 16 /** 17 * 18 * @描述 : 单个应用中的链接池最大链接数 19 * @创建时间: 2015年7月20日上午11:11:10 20 * 21 * @param maxTotal 22 */ 23 public void setMaxTotal(int maxTotal) { 24 this.jedisPoolConfig.setMaxTotal(maxTotal); 25 } 26 27 /** 28 * @描述 :单个应用中的链接池最大空闲数 29 * @创建时间: 2015年7月20日上午11:11:28 30 * 31 * @param maxIdle 32 */ 33 34 35 public void setMaxIdle(int maxIdle) { 36 this.jedisPoolConfig.setMaxIdle(maxIdle); 37 } 38 39 40 /** 41 * @描述 : 单个应用中的链接池最大链接数 42 * @创建时间: 2015年7月20日上午11:11:43 43 * 44 * @param maxIdle 45 */ 46 public void setMinIdle(int minIdle) { 47 this.jedisPoolConfig.setMinIdle(minIdle); 48 } 49 50 /** 51 * @描述 : 设置在每一次取对象时测试ping 52 * @创建时间: 2015年7月20日上午11:11:58 53 * 54 * @param flag 55 */ 56 public void setTestOnBorrow(boolean flag) { 57 this.jedisPoolConfig.setTestOnBorrow(flag); 58 } 59 60 public GenericObjectPoolConfig getJedisPoolConfig() { 61 return this.jedisPoolConfig; 62 } 63 64 public String getIpConfString() { 65 return this.ipConfString; 66 } 67 68 public void setIpConfString(String ipConfString) { 69 this.ipConfString = ipConfString; 70 } 71 }

相关热词:

本站内容来源于网络,如有侵权请与我们联系,我们会及时删除,我们深感抱歉!
注:本站所有信息仅供用于网络技术学习参考,学习中请遵循相关法律法规!

本文地址: https://v30.fanwenzhu.com/server/equal/11917.shtml

最新文章
ZooKeeper集群安装 ZooKeeper集群安装

时间:2021-01-10

KeepAlive详解 KeepAlive详解

时间:2021-01-10

Spark教程 构建Spark集群( Spark教程 构建Spark集群(

时间:2021-01-10

高效搭建Spark完全分布式集 高效搭建Spark完全分布式集

时间:2021-01-10

负载均衡与缓存 负载均衡与缓存

时间:2021-01-10

Hadoop2.2.0NNHA详细配置+Cli Hadoop2.2.0NNHA详细配置+Cli

时间:2021-01-10

Mongodb集群搭建过程及常见 Mongodb集群搭建过程及常见

时间:2021-01-09

DRBD+HeartBeat架构实验 DRBD+HeartBeat架构实验

时间:2021-01-09

Copyright © www.juheyunku.com      关于 | 合作 | 声明 | 联系 | 更新 | 地图 | Tags

redis + 主从 + 持久化 + 分片 + 集群 + spring集成

2021-01-08 编辑:网友投稿

Redis是一个基于内存的数据库,其不仅读写速度快,每秒可以执行大约110000的写操作,81000的读取操作,而且其支持存储字符串,哈希结构,链表,集合丰富的数据类型。所以得到很多开发者的青睐。加之其支持主从、持久化等功能,3.0版本开始正式提供分片技术、让其在大型互联网应用中大显身手,本文通过实际操作和理论相配合,对redis进行详细地阐述。

一、redis的安装与使用

下载直接去redis的官网进行不同操作系统对应的版本。本文中采用的redis的版本为3.2.5、linux平台,安装过程如下

[root@hbase usr]# tar -zxf redis-3.2.5.tar.gz [root@hbase usr]# cd redis-3.2.5 [root@hbase redis-3.2.5]# ll [root@hbase redis-3.2.5]# make [root@hbase redis-3.2.5]# cd src [root@hbase src]# ll

之后我们会发现其中redis-server和redis-cli,这两个文件分别对应启动redis的服务端和客户端,启动服务端

[root@hbase src]# ./redis-server 11579:M 13 Nov 15:07:01.399 # Warning: 32 bit instance detected but no memory limit set. Setting 3 GB maxmemory limit with 'noeviction' policy now. _._ _.-``__ ''-._ _.-`` `. `_. ''-._ Redis 3.2.5 (00000000/0) 32 bit .-`` .-```. ```/ _.,_ ''-._ ( ' , .-` | `, ) Running in standalone mode |`-._`-...-` __...-.``-._|'` _.-'| Port: 6379 | `-._ `._ / _.-' | PID: 11579 `-._ `-._ `-./ _.-' _.-' |`-._`-._ `-.__.-' _.-'_.-'| | `-._`-._ _.-'_.-' | `-._ `-._`-.__.-'_.-' _.-' |`-._`-._ `-.__.-' _.-'_.-'| | `-._`-._ _.-'_.-' | `-._ `-._`-.__.-'_.-' _.-' `-._ `-.__.-' _.-' `-._ _.-' `-.__.-' 11579:M 13 Nov 15:07:01.404 # Server started, Redis version 3.2.5 11579:M 13 Nov 15:07:01.409 * The server is now ready to accept connections on port 6379

可以看到,redis正常启动,6379 是 redis 服务端口,这个端口在redis.conf中可以进行配置,稍后我们讲解配置文件的时候会提到。不要关闭这个窗口,因为当前redis-server不是在后台运行,我们另起一个窗口,在当前目录下进行客户端连接服务端。

[hadoop@hbase src]$ ./redis-cli 127.0.0.1:6379>

说明一切正常,linux环境下的redis安装成功,至于windows下的安装过程相对更加简单,只需打开.exe文件即可,不在详细演示

二、redis数据类型

2.1 string

字符串类型是Redis中最为基础的数据存储类型,它在Redis中是二进制安全的,在Redis中字符串类型的Value最多可以容纳的数据长度是512M。除了get、set、作外,Redis还提供了其他的一些诸如追加、递增等功能。

set key value O(1) 设定该key对应的value,如果该Key已经存在,则覆盖其原有值。get key O(1) 获取指定Key的value,如果该Key不存在,返回nil。

setnx key value O(1) 如果指定的Key不存在,则设定该Key持有指定字符串value,此时其效果等价于set命令。如果该Key已经存在,该命令将不做任何操作。 

1 127.0.0.1:6379> set hello word 2 OK 3 127.0.0.1:6379> get hello 4 'word' 5 127.0.0.1:6379> set hello world 6 OK 7 127.0.0.1:6379> set hello world 8 OK 9 127.0.0.1:6379> get hello 10 'world' 11 127.0.0.1:6379> get world 12 (nil) 13 127.0.0.1:6379> set hello world_new 14 OK 15 127.0.0.1:6379> get hello 16 'world_new' 17 127.0.0.1:6379> setnx hello nihao 18 (integer) 0 19 127.0.0.1:6379> setnx new_hello nihao 20 (integer) 1

mset key value [key value ...] O(N) N表示指定Key的数量。该命令可以看成是多次迭代执行set命令。

mget key [key ...] O(N) N表示获取Key的数量。返回所有指定key的value,如果其中某个key不存在,该key的value将返回nil。 

msetnx key value [key value ...] O(N) N表示指定key的数量。该命令原子性的完成参数中所有key/value的设置操作,其具体行为可以看成是多次迭代执行setnx命令。如果在这一批keys中有任意一个key已经存在,那么该操作将全部回滚,即所有的修改都不会生效。 1表示所有keys都设置成功,0则表示没有任何key被修改。 

1 127.0.0.1:6379> mset key1 hello key2 world 2 OK 3 127.0.0.1:6379> mget key1 key2 4 1) 'hello' 5 2) 'world' 6 127.0.0.1:6379> mget key1 key3 7 1) 'hello' 8 2) (nil) 9 127.0.0.1:6379> msetnx key1 nihao key3 hi 10 (integer) 0 11 127.0.0.1:6379> msetnx key3 nihao key4 hi 12 (integer) 1

append key value  O(1) 若key已经存在,将value的数据追加到对应key的value的末尾。如果该key不存在,append命令将会创建一个新的key/value。

strlen key O(1) 返回指定Key的字符值长度,如果该Key不存在,返回0。

decr key O(1) 将指定key的value原子性的递减1。如果该key不存在,其初始值为0,在decr之后其值为-1。如果value的值不能转换为整型值,该操作将执行失败。

incr key O(1) 将指定key的value原子性的递增1。如果该Key不存在,其初始值为0,在incr之后其值为1。如果value的值不能转换为整型值,该操作将执行失败。 

decrby key decrement O(1) 将指定key的value原子性的减少decrement,其他同decr。

incrby key increment O(1) 将指定key的value原子性的增加increment,其他同incr。 

1 127.0.0.1:6379> append k1 hello 2 (integer) 5 3 127.0.0.1:6379> append k1 world 4 (integer) 10 5 127.0.0.1:6379> get k1 6 'helloworld' 7 127.0.0.1:6379> strlen k1 8 (integer) 10 9 127.0.0.1:6379> set k2 1 10 OK 11 127.0.0.1:6379> incr k2 12 (integer) 2 13 127.0.0.1:6379> get k2 14 '2' 15 127.0.0.1:6379> decr k2 16 (integer) 1 17 127.0.0.1:6379> get k2 18 '1' 19 127.0.0.1:6379> incrby k2 5 20 (integer) 6 21 127.0.0.1:6379> decrby k2 5 22 (integer) 1 23 127.0.0.1:6379> get k2 24 '1'

2.2 redis之数据类型list

在Redis中,List类型是按照插入顺序排序的字符串链表。和数据结构中的普通链表一样,我们可以在其头部(left)和尾部(right)添加新的元素,该操作也可以在常量时间内完成。在插入时,如果该键并不存在,Redis将为该键创建一个新的链表。与此相反,如果链表中所有的元素均被移除,那么该键也将会被从数据库中删除。List中可以包含的最大元素数量是4294967295。 

lpush key value [value ...] O(1) 在指定key所对应的List头部插入所有values。如果该Key不存在,则插入之前创建一个与该key关联的空链表。

lpop key O(1) 返回并弹出指定key对应链表的第一个元素。如果该Key不存在,返回nil。

lrange key start stop start和end都是0-len,即0表示链表头部的第一个元素。其中start的值也可以为负值,-1将表示链表中的最后一个元素,即尾部元素,-2表示倒数第二个并以此类推。该命令在获取元素时,start和end位置上的元素也会被取出。如果start的值大于链表中元素的数量,空链表将会被返回。如果end的值大于元素的数量,该命令则获取从start(包括start)开始,链表中剩余的所有元素。 

lpushx key value O(1) 当指定的key存在时,在其所关联的list的头部插入参数中给出的value,否则将不会有任何操作发生。    

lrem key count value O(N) 在指定key关联的链表中,删除前count个值等于value的元素。如果count大于0,从头向尾遍历并删除,如果count小于0,则从尾向头遍历并删除。如果count等于0,则删除链表中所有等于value的元素。如果指定的key不存在,则直接返回0。

llen key O(1) 返回指定key关联的链表中元素的数量,如果该Key不存在,则返回0。。

lset  key index value O(N) 设定链表中指定位置的值为新值,其中0表示第一个元素,即头部元素,-1表示尾部元素。 

1 127.0.0.1:6379> lpush k1 v1 v2 v3 2 (integer) 3 3 127.0.0.1:6379> lrange k1 0 2 4 1) 'v3' 2) 'v2' 3) 'v1' 5 127.0.0.1:6379> lpop k1 6 'v3' 7 127.0.0.1:6379> lrange k1 0 2 8 1) 'v2' 2) 'v1' 9 127.0.0.1:6379> lpush k1 v4 10 (integer) 3 11 127.0.0.1:6379> lrange k1 0 2 12 1) 'v4' 2) 'v2' 3) 'v1' 13 127.0.0.1:6379> lpush k1 v4 14 (integer) 4 15 127.0.0.1:6379> lpush k1 v4 16 (integer) 5 17 127.0.0.1:6379> lpush k1 v4 18 (integer) 6 19 127.0.0.1:6379> lrange k1 0 5 20 1) 'v4' 2) 'v4' 3) 'v4' 4) 'v4' 5) 'v2' 6) 'v1' 21 127.0.0.1:6379> lrem k1 2 v4 # 删除前两个值为v4的元素 22 (integer) 2 23 127.0.0.1:6379> lrange k1 0 3 24 1) 'v4' 2) 'v4' 3) 'v2' 4) 'v1' 25 127.0.0.1:6379> llen k1 26 (integer) 4 27 127.0.0.1:6379> lset k1 1 k5 #设置索引为1的值为k5 28 OK 29 127.0.0.1:6379> lrange k1 0 3 30 1) 'v4' 2) 'k5' 3) 'v2' 4) 'v1'

rpush key value [value ...] O(1) 在指定key所对应的List尾部插入所有values。如果该Key不存在,则插入之前创建一个与该key关联的空链表。

rpop key O(1) 返回并弹出指定key对应链表的最后一个元素。如果该Key不存在,返回nil。

rpushx key value O(1) 当指定的key存在时,在其所关联的list的尾部插入参数中给出的value,否则将不会有任何操作发生。  

1 127.0.0.1:6379> lrange k1 0 3 2 1) 'v4' 2) 'k5' 3) 'v2' 4) 'v1' 3 127.0.0.1:6379> rpushx k1 k6 4 (integer) 5 5 127.0.0.1:6379> lrange k1 0 4 6 1) 'v4' 2) 'k5' 3) 'v2' 4) 'v1' 5) 'k6' 7 127.0.0.1:6379> rpush k1 k7 k8 #在尾部添加元素 8 (integer) 7 9 127.0.0.1:6379> lrange k1 0 6 10 1) 'v4' 2) 'k5' 3) 'v2' 4) 'v1' 5) 'k6' 6) 'k7' 7) 'k8' 11 127.0.0.1:6379> rpop k1 #弹出尾部的元素 12 'k8' 13 127.0.0.1:6379> lrange k1 0 5 14 1) 'v4' 2) 'k5' 3) 'v2' 4) 'v1' 5) 'k6' 6) 'k7' 15 127.0.0.1:6379>

2.3 hash

Redis hash 是一个string类型的field和value的映射表,hash特别适合用于存储对象。每一个Hash可以存储4294967295个键值对。

hset key field value O(1) 为指定的key设置field/value对,若key不存在,则创建新key,并创建field/value对,若该key中已经存在,则用新值覆盖其原有值。

hget key field O(1) 返回指定key中指定field所对应的值,若key或field不存在,返回nil。

hmget key field [field ...] O(N) 获取指定fields关联的一组values。如果请求的field不存在,其值返回nil。

hmset key field value [field value ...] O(N) 逐个依次设置参数中给出的field/value对。如果其中某个field已经存在,则用新值覆盖原有值。如果key不存在,则创建新key,同时设定参数中的field/value。

hsetnx key field value O(1) 只有当key或field不存在时,为指定的key设定field/value对,否则该命令不会进行任何操作。

1 127.0.0.1:6379> hset k1 f1 v1 2 (integer) 1 3 127.0.0.1:6379> hset k1 f2 v2 4 (integer) 1 5 127.0.0.1:6379> hget k1 f1 6 'v1' 7 127.0.0.1:6379> hmget k1 f1 f2 8 1) 'v1' 2) 'v2' 9 127.0.0.1:6379> hmset k1 f3 v3 f4 v4 10 OK 11 127.0.0.1:6379> hmget k1 f1 f2 f3 f4 12 1) 'v1' 2) 'v2' 3) 'v3' 4) 'v4' 13 127.0.0.1:6379> hsetnx k1 f1 v5 14 (integer) 0 15 127.0.0.1:6379> hsetnx k1 f5 v5 16 (integer) 1 17 127.0.0.1:6379> hmget k1 f1 f2 f3 f4 f5 18 1) 'v1' 2) 'v2' 3) 'v3' 4) 'v4' 5) 'v5'

hkeys key O(N) 返回指定key的所有fields名。

hvals key O(N) 返回指定Key的所有values名。

hexists key field O(1) 判断指定key中的指定field是否存在。1表示存在,0表示field或key不存在。

hlen key O(1) 获取该key所包含的field的数量。返回key包含的field数量,如果key不存在,返回0。

hdel key field [field ...] O(N) 从指定key的hash中删除指定的多个字段,如果不存在的字段将被忽略。

hincrby key field increment O(1) 增加指定key中指定field对应的value的值。如果key或field不存在,该命令将会创建一个新key或新field。 

1 127.0.0.1:6379> hkeys k1 2 1) 'f1' 2) 'f2' 3) 'f3' 4) 'f4' 5) 'f5' 3 127.0.0.1:6379> hvals k1 4 1) 'v1' 2) 'v2' 3) 'v3' 4) 'v4' 5) 'v5' 5 127.0.0.1:6379> hexists k1 f1 6 (integer) 1 7 127.0.0.1:6379> hlen k1 8 (integer) 5 9 127.0.0.1:6379> hdel k1 f5 10 (integer) 1 11 127.0.0.1:6379> hset k1 f5 1 12 (integer) 1 13 127.0.0.1:6379> hvals k1 14 1) 'v1' 2) 'v2' 3) 'v3' 4) 'v4' 5) '1' 15 127.0.0.1:6379> hincrby k1 f5 2 16 (integer) 3 17 127.0.0.1:6379> hvals k1 18 1) 'v1' 2) 'v2' 3) 'v3' 4) 'v4' 5) '3'

2.4 set

在Redis中, Set类型看作为没有排序的字符集合,和List类型一样,我们也可以在该类型的数据值上执行添加、删除或判断某一元素是否存在等操作。set可包含的最大元素数量是4294967295。set集合中不允许出现重复的元素。 

sadd key member [member ...] O(N) 若该Key不存在,该命令将会创建一个新的set。若有的成员在set中已经存在,该成员将被忽略,而其它成员仍将会被正常插入。

spop key O(1) 随机的移除并返回set中的某一成员。

scard key O(1) 获取set中成员的数量。

sismember key member O(1) 判断参数中指定成员是否已经存在于与key所在的set集合中。

smembers key O(N) 获取与该key关联的set中所有的成员。     

srem key member [member ...] O(N) 从与key关联的set中删除参数中指定的成员,不存在的参数成员将被忽略。

1 127.0.0.1:6379> sadd k1 m1 2 (integer) 1 3 127.0.0.1:6379> sadd k1 m2 4 (integer) 1 5 127.0.0.1:6379> scard k1 6 (integer) 2 7 127.0.0.1:6379> spop k1 8 'm2' 9 127.0.0.1:6379> sadd k1 m3 10 (integer) 1 11 127.0.0.1:6379> sismember k1 m3 12 (integer) 1 13 127.0.0.1:6379> smembers k1 14 1) 'm3' 15 2) 'm1' 16 127.0.0.1:6379> srem k1 m1 17 (integer) 1 18 127.0.0.1:6379> smembers k1 19 1) 'm3'

sdiff key [key ...] O(N) 返回第一个key所关联的set和其后所有keys所关联的sets中成员的差异。

sinter  key [key ...] O(N*M) 返回参数中所有keys关联的sets中成员的交集。

sunion key [key ...] O(N) 返回参数中所有keys关联的sets中成员的并集。  

127.0.0.1:6379> smembers k1 1) 'm2' 2) 'm1' 3) 'm3' 127.0.0.1:6379> smembers k2 1) 'm3' 2) 'm1' 3) 'm4' 127.0.0.1:6379> sdiff k1 k2 1) 'm2' 127.0.0.1:6379> sinter k1 k2 1) 'm1' 2) 'm3' 127.0.0.1:6379> sunion k1 k2 1) 'm3' 2) 'm1' 3) 'm2' 4) 'm4'

2.5 sorted set

sorted-set和set类型极为相似,都不允许重复的成员出现在一个Set中。它们之间的主要差别是sorted-set中的每一个成员都会有一个分数(score)与之关联,Redis正是通过分数来为集合中的成员进行从小到大的排序。

zadd key score member [score] [member] O(log(N)) 添加参数中指定的所有成员及其分数到指定key的sorted-sett中。

zcard key O(1) 获取与该key相关联的sorted-set中包含的成员数量。

zscore key member O(1) 获取指定Key的指定成员的分数。如果该成员存在,以字符串的形式返回其分数,否则返回nil。

zcount key min max O(log(N)+M) 用于获取分数(score)在min和max之间的成员数量。min和max表示的范围是闭区间范围,即min <= score <= max内的成员将被返回。

zincrby key increment member O(log(N)) 将为指定Key中的指定成员增加指定的分数。

zrange key start stop [WITHSCORES] O(log(N)+M)  返回顺序在start和stop指定范围内的成员列表。

zrangebyscore key min max [WITHSCORES] [LIMIT offset count] O(log(N)+M) 将返回分数在min和max之间的所有成员列表。

zrem key member [member ...] O(M log(N)) 移除参数中指定的成员,其中不存在的成员将被忽略。

zremrangebyscore key min max O(log(N)+M) 删除分数在min和max之间的所有成员,即满足表达式min <= score <= max的所有成员。 

1 127.0.0.1:6379> zadd k1 1 m1 2 (integer) 1 3 127.0.0.1:6379> zadd k1 2 m2 4 (integer) 1 5 127.0.0.1:6379> zadd k1 3 m3 6 (integer) 1 7 127.0.0.1:6379> zcard k1 8 (integer) 3 9 127.0.0.1:6379> zscore k1 m1 10 '1' 11 127.0.0.1:6379> zscore k1 m2 12 '2' 13 127.0.0.1:6379> zcount k1 2 3 14 (integer) 2 15 127.0.0.1:6379> zincrby k1 3 m3 16 '6' 17 127.0.0.1:6379> zrange k1 1 10 18 1) 'm2' 19 2) 'm3' 20 127.0.0.1:6379> zrange k1 0 10 21 1) 'm1' 22 2) 'm2' 23 3) 'm3' 24 127.0.0.1:6379> zcount k1 0 10 25 (integer) 3 26 127.0.0.1:6379> zrangebyscore k1 0 6 27 1) 'm1' 28 2) 'm2' 29 3) 'm3' 30 127.0.0.1:6379> zrem k1 m1 31 (integer) 1 32 127.0.0.1:6379> zcard k1 33 (integer) 2 34 127.0.0.1:6379> zremrangebyscore k1 2 3 35 (integer) 1 36 127.0.0.1:6379> zremrangebyscore k1 2 10 37 (integer) 1 38 127.0.0.1:6379> zcard k1 39 (integer) 0

三、redis的相关命令 

keys pattern O(N) 获取所有匹配pattern参数的Keys。需要说明的是,在我们的正常操作中应该尽量避免对该命令的调用,因为对于大型数据库而言,该命令是非常耗时的。pattern支持glob-style的通配符格式,如*表示任意一个或多个字符,?表示任意字符,[abc]表示方括号中任意一个字母。
del key [key ...] O(N) 从数据库删除中参数中指定的keys,如果指定键不存在,则直接忽略。
exists key O(1) 判断指定键是否存在。 1表示存在,0表示不存在。
move key db O(1) 将当前数据库中指定的键key移动到参数中指定的数据库中。若该key在目标数据库中已经存在,或者在当前数据库中不存在,该命令将不做任何操作并返回0。 移动成功返回1,否则0。
rename key newkey O(1) 为指定指定的键重新命名,如果两个keys的命令相同,或者是源key不存在,该命令都会返回相关的错误信息。如果newKey已经存在,则直接覆盖。
renamenx key newkey O(1) 如果新值不存在,则将参数中的原值修改为新值。其它条件和rename一致。1表示修改成功,否则0。
expire key seconds O(1) 该命令为指定的key设定超时的秒数,在超过该时间后,key被自动的删除。如果该Key在超时之前被修改,与该键关联的超时将被移除。1表示超时被设置,0则表示Key不存在,或不能被设置。
expireat key timestamp O(1) 该命令的逻辑功能和expire完全相同,差别是该命令指定的超时时间是绝对时间,而不是相对时间。该时间参数是Unix timestamp格式的,即从1970年1月1日开始所流经的秒数。1表示超时被设置,0则表示Key不存在,或不能被设置。
ttl key O(1) 获取该键所剩的超时描述。如果该键不存在或没有超时设置,则返回-1。
type key O(1) 获取与参数中指定键关联值的类型,该命令将以字符串的格式返回。 返回的字符串为string、list、set、hash和zset,如果key不存在返回none。

1 127.0.0.1:6379> keys * 2 (empty list or set) 3 127.0.0.1:6379> set str string 4 OK 5 127.0.0.1:6379> hset hash3 f1 v1 6 (integer) 1 7 127.0.0.1:6379> sadd set1 v1 8 (integer) 1 9 127.0.0.1:6379> zadd sortedset1 1 v1 10 (integer) 1 11 127.0.0.1:6379> lpush list1 v1 v2 12 (integer) 2 13 127.0.0.1:6379> keys * 14 1) 'hash3' 15 2) 'sortedset1' 16 3) 'list1' 17 4) 'str' 18 5) 'set1' 19 127.0.0.1:6379> keys s* 20 1) 'sortedset1' 21 2) 'str' 22 3) 'set1' 23 127.0.0.1:6379> exists list1 24 (integer) 1 25 127.0.0.1:6379> rename list1 list2 26 OK 27 127.0.0.1:6379> keys * 28 1) 'hash3' 29 2) 'sortedset1' 30 3) 'str' 31 4) 'list2' 32 5) 'set1' 33 127.0.0.1:6379> type list2 34 list 35 127.0.0.1:6379> type str 36 string 37 127.0.0.1:6379> set str2 v2 38 OK 39 127.0.0.1:6379> expire str2 10 40 (integer) 1 41 127.0.0.1:6379> ttl str2 42 (integer) 6 43 127.0.0.1:6379> ttl str2 44 (integer) -2 45 127.0.0.1:6379> keys * 46 1) 'hash3' 47 2) 'sortedset1' 48 3) 'str' 49 4) 'list2' 50 5) 'set1' 51 127.0.0.1:6379> move str 1 52 (integer) 1 53 127.0.0.1:6379> keys * 54 1) 'hash3' 55 2) 'sortedset1' 56 3) 'list2' 57 4) 'set1' 58 127.0.0.1:6379> select 1 59 OK 60 127.0.0.1:6379[1]> keys * 61 1) 'str' 62 127.0.0.1:6379[1]> select 0 63 OK 64 127.0.0.1:6379> del set1 65 (integer) 1 66 127.0.0.1:6379> keys * 67 1) 'hash3' 68 2) 'sortedset1' 69 3) 'list2'

四、redis的事务

1). 所有命令顺序执行,期间,Redis不会再为其它客户端的请求提供任何服务,从而保证了事物中的所有命令被原子的执行。
2). 和关系型数据库中的事务不同的是,在Redis事务中如果有某一条命令执行失败,其后的命令仍然会被继续执行。
3). 我们可以通过MULTI命令开启一个事务,有关系型数据库开发经验的人可以将其理解为'BEGIN TRANSACTION'语句。在该语句之后执行的命令都将被视为事务之内的操作,最后我们可以通过执行EXEC/DISCARD命令来提交/回滚该事务内的所有操作。这两个Redis命令可被视为等同于关系型数据库中的COMMIT/ROLLBACK语句。

multi 用于标记事务的开始,其后执行的命令都将被存入命令队列,直到执行exec时,这些命令才会被原子的执行。 始终返回OK
exec 执行在一个事务内命令队列中的所有命令,同时将当前连接的状态恢复为正常状态,即非事务状态。如果在事务中执行了watch命令,那么只有当watch所监控的keys没有被修改的前提下,exec命令才能执行事务队列中的所有命令,否则exec将放弃当前事务中的所有命令。 原子性的返回事务中各条命令的返回结果。如果在事务中使用了watch,一旦事务被放弃,exec将返回NULL-multi-bulk回复。

1 127.0.0.1:6379> multi 2 OK 3 127.0.0.1:6379> set k1 string 4 QUEUED 5 #由于k1为字符串类型,所以incr会报错,但是以后其他命令正常执行 6 127.0.0.1:6379> incr k1 7 QUEUED 8 127.0.0.1:6379> set k1 newstring 9 QUEUED 10 127.0.0.1:6379> get k1 11 QUEUED 12 127.0.0.1:6379> exec 13 1) OK 14 2) (error) ERR value is not an integer or out of range 15 3) OK 16 4) 'newstring'

discard 回滚事务队列中的所有命令,同时再将当前连接的状态恢复为正常状态,即非事务状态。如果watch命令被使用,该命令将unwatch所有的Keys。
watch key [key ...] O(1) 在multi命令执行之前,可以指定待监控的keys,然而在执行exec之前,如果被监控的keys发生修改,exec将放弃执行该事务队列中的所有命令。
unwatch O(1) 取消当前事务中指定监控的keys,如果执行了exec或discard命令,则无需手工执行该命令,因为事务中所有被监控的keys都将自动取消。 

1 127.0.0.1:6379> set id 1 2 OK 3 127.0.0.1:6379> set name n1 4 OK 5 127.0.0.1:6379> set age 12 6 OK 7 127.0.0.1:6379> watch id 8 OK 9 127.0.0.1:6379> multi 10 OK 11 127.0.0.1:6379> set name n2 12 QUEUED 13 127.0.0.1:6379> incr age 14 QUEUED 15 127.0.0.1:6379> exec 16 (nil) 17 127.0.0.1:6379> get age 18 '12' 19 127.0.0.1:6379> get name 20 'n1'

注意,在提交事务之前,则执行exec命令之前,我们在另一个窗口对id进行修改(set id 2),可以看出,该事务没有执行成功

五、redis的主从复制

1). 同一个Master可以同步多个Slaves节点。

2). Slave同样可以接受其它Slaves的连接和同步请求。

3). Master Server是以非阻塞的方式为Slaves提供服务。所以在Master-Slave同步期间,客户端仍然可以提交查询或修改请求。

4). Slave Server同样是以非阻塞的方式完成数据同步。在同步期间,如果有客户端提交查询请求,Redis则返回同步之前的数据。

5). 为了分载Master的读操作压力,Slave服务器可以为客户端提供只读操作的服务,写服务仍然必须由Master来完成。从而实现读写分离

在Slave启动并连接到Master之后,它将主动发送一个SYNC命令。此后Master将启动后台存盘进程,同时收集所有接收到的用于修改数据集的命令,在后台进程执行完毕后,Master将传送整个数据库文件到Slave,以完成一次完全同步。而Slave服务器在接收到数据库文件数据之后将其存盘并加载到内存中。此后,Master继续将所有已经收集到的修改命令,和新的修改命令依次传送给Slaves,Slave将在本次执行这些数据修改命令,从而达到最终的数据同步。若Master和Slave之间的链接出现断连现象,Slave可以自动重连Master,但是在连接成功之后,一次完全同步将被自动执行。 

同时启动两个Redis服务器,可以考虑在同一台机器上启动两个Redis服务器,分别监听不同的端口,如6379和6380。复制redis.conf并命名为slave.conf,编辑该配置文件,在84行位置将其中监听的端口改为6380:配置如下port 6380,分配启动两个server,启动时可以将配置文件作为启动命令的参数。命令如下:redis-server redis.conf ,当我们把两个server都启动时,可以进行以下步骤:

1 redis-cli -p 6380

通过不同的端口来链接服务端,此时,当前客户端链接的6380端口的服务端,我们让这个服务端当做slave节点的角色。执行如下命令

slaveof 127.0.0.1 6379

当返回ok时,这里我Master-Slave建立成功。在监听端口为6379的服务器上我们用客户端进行操作

1 [root@hbase redis-3.2.5]# src/redis-cli -p 6379 2 127.0.0.1:6379> set k1 v1 3 OK 4 127.0.0.1:6379> hset k2 f2 v2 5 (integer) 1 6 127.0.0.1:6379>

在slave节点,获取该值:

1 [root@hbase redis-3.2.5]# src/redis-cli -p 6380 2 127.0.0.1:6380> slaveof 127.0.0.1 6379 3 OK 4 127.0.0.1:6380> keys * 5 1) 'k1' 6 2) 'k2' 7 127.0.0.1:6380> get k1 8 'v1'

说明两个节点主从已经同步。实现了主从同步的效果。需要注意的是:上面的方式只是保证了在执行slaveof命令之后,redis_6380成为了redis_6379的slave,一旦服务(redis_6380)重新启动之后,他们之间的复制关系将终止。如果希望长期保证这两个服务器之间的Replication关系,可以在redis_6380的配置文件中做如下修改:

# slaveof <masterip> <masterport>改为slaveof 127.0.0.1 6379

保存退出。这样就可以保证Redis_6380服务程序在每次启动后都会主动建立与Redis_6379的Replication连接了。

六、redis的持久化

6.1、Redis提供的持久化机制: 

1). RDB持久化:该机制是指在指定的时间间隔内将内存中的数据集快照写入磁盘。 

2). AOF持久化:该机制将以日志的形式记录服务器所处理的每一个写操作,在Redis服务器启动之初会读取该文件来重新构建数据库,以保证启动后数据库中的数据是完整的。

6.2、RDB机制的优势和劣势:

优势:
1). 采用该方式,整个Redis数据库将只包含一个文件,通过这样的备份策略,一旦系统出现灾难性故障,我们可以非常容易的进行恢复。
2). 性能最大化,对于Redis的服务进程而言,在开始持久化时,它唯一需要做的只是fork出子进程,再由子进程完成这些持久化的工作,这样可以极避免服务进程执行IO操作。
劣势:

1). 如果你想保证数据的高可用性,那么RDB将不是一个很好的选择。因为系统一旦在定时持久化之前出现宕机现象,此前没有来得及写入磁盘的数据都将丢失。

2). 由于RDB是通过fork子进程来协助完成数据持久化工作的,因此,如果当数据集较大时,可能会导致整个服务器停止服务一定的时间。

6.3、AOF机制的优势和劣势: 

优势
1). 带来更高的数据安全性,即数据持久性。Redis中提供了3中同步策略,即每秒同步、每修改同步和不同步。事实上,每秒同步也是异步完成的,其效率也是非常高的,所差的是一旦系统出现宕机现象,那么这一秒钟之内修改的数据将会丢失。而每修改同步,我们可以将其视为同步持久化,即每次发生的数据变化都会被立即记录到磁盘中。可以预见,这种方式在效率上是最低的。

2). 由于该机制对日志文件的写入操作采用的是append模式,因此在写入过程中即使出现宕机现象,也不会破坏日志文件中已经存在的内容。然而如果我们本次操作只是写入了一半数据就出现了系统崩溃问题,在Redis下一次启动之前,可以通过redis-check-aof工具来解决数据一致性的问题。

3). 如果日志过大,Redis可以自动启用rewrite机制。即Redis以append模式不断的将修改数据写入到老的磁盘文件中,同时Redis还会创建一个新的文件用于记录此期间有哪些修改命令被执行。因此在进行rewrite切换时可以更好的保证数据安全性。

4). AOF包含一个格式清晰、易于理解的日志文件用于记录所有的修改操作。事实上,我们也可以通过该文件完成数据的重建。
劣势
1). 对于相同数量的数据集而言,AOF文件通常要大于RDB文件。
2). 根据同步策略的不同,AOF在运行效率上往往会慢于RDB。

介绍完理论之后,我们配置redis的持久化方案:

rdb方案,在redis.conf中如下配置(默认配置) 

1 save 900 1 #在900秒(15分钟)之后,如果至少有1个key发生变化,则dump内存快照。 2 save 300 10 #在300秒(5分钟)之后,如果至少有10个key发生变化,则dump内存快照。 3 save 60 10000 #在60秒(1分钟)之后,如果至少有10000个key发生变化,则dump内存快照。

aof方案的配置:

1 在Redis的配置文件中存在三种同步方式,它们分别是: 2 appendfsync always #每次有数据修改发生时都会写入AOF文件。 3 appendfsync everysec #每秒钟同步一次,该策略为AOF的缺省策略。 4 appendfsync no #从不同步。高效但是数据不会被持久化。

七、redis的分片

分片(partitioning)就是将你的数据拆分到多个 Redis 实例的过程,Redis 引入另一种哈希槽(hash slot)的概念。Redis 集群中内置了 16384 个哈希槽,当需要在 Redis 集群中放置一个 key-value 时,redis 先对 key 使用 crc16 算法得出结果,然后对 16384 求余数,这样每个 key 对应一个编号在 0-16383 之间的哈希槽,redis 会根据节点数量大致均等的将哈希槽映射到不同节点。

原来的redis分片实现:

客户端分片(Client side partitioning),客户端直接选择正确的节点来写入和读取指定键。

代理协助分片(Proxy assisted partitioning),客户端发送请求到一个可以理解 Redis 协议的代理上,而不是直接发送请求到 Redis 实例上。代理会根据配置好的分片模式,来保证转发请求到正确的 Redis 实例,并返回响应给客户端。

查询路由(Query routing),发送查询到一个随机实例,这个实例会保证转发查询到正确的节点。 

新版本Redis的解决办法:

Redis3.0版的一大特性就是支持集群(Cluster)功能。Redis集群是自动分片和高可用的首选方式。集群的特点在于拥有和单机实例同样的功能,同时在网络分区后能够提供一定的可访问性以及对主数据库故障恢复的支持。

搭建redis集群环境需要执行的ruby的脚本,所以需要安装ruby的环境。建议用yum进行安装,由于具体的操作环境不相同,所以具体操作过程还需视操作环境而定 

1 [root@root java]# yum install ruby 2 [root@root java]# yum install rubygems 3 [root@root java]# gem install redis

期间会出现选择选项,键入yes即可。当出现Successfully installed redis-3.3.1  1 gem installed,说明redis集群需要的ruby环境安装成功。开始搭建redis环境

创建redis-cluster文件夹,并在其中创建6379,6380,6381文件夹,修改redis.conf文件,并将其中的端口分别设置成6379,6380,6381,redis.conf中的其他配置为

daemonize yes

cluster-enabled yes

cluster-config-file nodes.conf

cluster-node-timeout 5000

appendonly yes

结构目录如下:

1 [root@storm1 java]# cd redis-cluster/ 2 [root@storm1 redis-cluster]# ll 3 total 12 4 drwxr-xr-x. 2 root root 4096 Nov 14 05:50 6379 5 drwxr-xr-x. 2 root root 4096 Nov 14 05:51 6380 6 drwxr-xr-x. 2 root root 4096 Nov 14 05:52 6381 7 [root@storm1 redis-cluster]# cd 6379 8 [root@storm1 6379]# cat redis.conf 9 port 6379 10 daemonize yes 11 cluster-enabled yes 12 cluster-config-file nodes.conf 13 cluster-node-timeout 5000 14 appendonly yes[root@storm1 6379]# more ../6380/redis.conf 15 port 6380 16 daemonize yes 17 cluster-enabled yes 18 cluster-config-file nodes.conf 19 cluster-node-timeout 5000 20 appendonly yes 21 [root@storm1 6379]#

分别启动这3个redis实例,并创建集群,让三个实例互相通讯:

1 [root@storm1 redis-3.2.5]# src/redis-trib.rb create --replicas 0 127.0.0.1:6379 127.0.0.1:6380 127.0.0.1:6381 2 >>> Creating cluster 3 >>> Performing hash slots allocation on 3 nodes... 4 Using 3 masters: 5 127.0.0.1:6379 6 127.0.0.1:6380 7 127.0.0.1:6381 8 M: 76d37cdb954e0c293cec5c6bc27015af40d4a59f 127.0.0.1:6379 9 slots:0-5460 (5461 slots) master 10 M: f18ab812b7f9e933639b3afdab964039ddd3ceba 127.0.0.1:6380 11 slots:5461-10922 (5462 slots) master 12 M: 644f9bca1af9cc9e3f1543ab5f0b434d11ff59b0 127.0.0.1:6381 13 slots:10923-16383 (5461 slots) master 14 Can I set the above configuration? (type 'yes' to accept): yes 15 >>> Nodes configuration updated 16 >>> Assign a different config epoch to each node 17 >>> Sending CLUSTER MEET messages to join the cluster 18 Waiting for the cluster to join.... 19 >>> Performing Cluster Check (using node 127.0.0.1:6379) 20 M: 76d37cdb954e0c293cec5c6bc27015af40d4a59f 127.0.0.1:6379 21 slots:0-5460 (5461 slots) master 22 0 additional replica(s) 23 M: 644f9bca1af9cc9e3f1543ab5f0b434d11ff59b0 127.0.0.1:6381 24 slots:10923-16383 (5461 slots) master 25 0 additional replica(s) 26 M: f18ab812b7f9e933639b3afdab964039ddd3ceba 127.0.0.1:6380 27 slots:5461-10922 (5462 slots) master 28 0 additional replica(s) 29 [OK] All nodes agree about slots configuration. 30 >>> Check for open slots... 31 >>> Check slots coverage... 32 [OK] All 16384 slots covered.

至此redis集群即搭建成功,简单进行测试一下

1 [root@storm1 redis-3.2.5]# src/redis-cli -c -p 6379 2 127.0.0.1:6379> set k1 v1 3 -> Redirected to slot [12706] located at 127.0.0.1:6381 4 OK 5 127.0.0.1:6381> exit 6 [root@storm1 redis-3.2.5]# src/redis-cli -c -p 6381 7 127.0.0.1:6381> keys * 8 1) 'k1' 9 127.0.0.1:6381>

可以看到,虽然我们第一次连接的是6379端口,redis cluster 自动帮我们重定向到 6381 。在6381端口的实例中出现了我们之前设置的k1,说明整个集群是工作的。

八、redis的管理命令

config get parameter 用于读取服务器的运行时参数,但是并不是所有的配置参数都可以通过该命令进行读取。该命令的参数接受glob风格的模式匹配规则,因此如果参数中包含模式元字符,那么所有匹配的参数都将以key/value方式被列出。如果参数是*,那么该命令支持的所有参数都将被列出。

config set parameter value 该命令用于配置Redis服务器的运行时参数,在设置成功之后无需重启便可生效。然而并非所有的参数都可以通过该命令进行动态设置。
dbsize 返回当前打开的数据库中keys的数量。
flushall  清空当前服务器管理的数据库中的所有keys,不仅限于当前打开的数据库。
flushdb  清空当前数据库中的所有keys。
info  获取和服务器运行状况相关的一些列统计数字。
save 设置RDB持久化模式的保存策略。
shutdown  停止所有的客户端,同时以阻塞的方式执行内存数据持久化。如果AOF模式被启用,则将缓存中的数据flush到AOF文件。退出服务器。
slaveof host port 该命令用于修改slave服务器的主从复制设置。
slowlog subcommand [argument] 该命令主要用于读取执行时间较长的命令。由于slowlog队列不会被持久化到磁盘,因此Redis在收集命令时不会对性能产生很大的影响。通常我们可以将参数'slowlog-log-slower-than'设置为0,以便收集所有命令的执行时间。该命令还包含以下几个子命令:
1). slowlog get N: 从slowlog队列中读取命令信息,N表示最近N条命令的信息。
2). slowlog len:获取slowlog队列的长度。
3). slowlog reset:清空slowlog中的内容。

1 redis 127.0.0.1:6379> config get port 2 1) 'port' 3 2) '6379' 4 redis 127.0.0.1:6379> keys * 5 1) 'k1' 6 redis 127.0.0.1:6379> flushdb 7 OK 8 redis 127.0.0.1:6379> keys * 9 (empty list or set) 10 redis 127.0.0.1:6379> dbsize 11 (integer) 0 12 redis 127.0.0.1:6379> set k1 v1 13 OK 14 redis 127.0.0.1:6379> dbsize 15 (integer) 1

九、redis的java操作

maven依赖 

1 <dependency> 2 <groupId>redis.clients</groupId> 3 <artifactId>jedis</artifactId> 4 <version>2.6.2</version> 5 <type>jar</type> 6 <scope>compile</scope> 7 </dependency>

java代码:

1 import redis.clients.jedis.Jedis; 2 3 public class RedisDao { 4 5 public static void main(String[] args) { 6 Jedis jedis = new Jedis('127.0.0.1', 6379); 7 jedis.set('k2', 'v2'); 8 System.out.println(jedis.get('k2')); 9 jedis.hset('k3', 'f1', 'v1'); 10 System.out.println(jedis.hget('k3', 'f1')); 11 System.out.println(jedis.keys('*')); 12 jedis.close(); 13 } 14 }

十、redis与spring整合 

10.1 引入jedis包和spring包

10.2 spring-mvc.xml 

1 <?xml version='1.0' encoding='UTF-8'?> 2 <beans xmlns='' xmlns:xsi='' xmlns:context='' xsi:schemaLocation=' http://www.springframework.org/schema/beans/spring-beans.xsd 3 http://www.springframework.org/schema/context/spring-context.xsd' default-autowire='byName'> 4 5 <bean id='redisClient' class='com.eztcn.commons.redis.RedisClientFactoryBean'> 6 <!-- 单个应用中的链接池最大链接数,默认8 --> 7 <property name='maxTotal' value='150' /> 8 <!-- 单个应用中的链接池最大空闲数,默认8 --> 9 <property name='maxIdle' value='50' /> 10 <!-- 单个应用中的链接池最大链接数,默认8 --> 11 <property name='minIdle' value='30' /> 12 <!-- 设置在每一次取对象时测试ping --> 13 <property name='testOnBorrow' value='false' /> 14 <!-- host:port --> 15 <property name='ipConfString' value='192.168.1.60:7001' /> 16 </bean> 17 </beans>

当然需要在spring配置文件中引入该配置文件:<import resource='spring/spring-config-redis.xml' />

10.3 RedisClientFactoryBean.java 

1 package com.commons.redis; 2 3 import org.apache.commons.lang3.StringUtils; 4 import org.springframework.beans.factory.FactoryBean; 5 6 public class RedisClientFactoryBean implements FactoryBean<RedisClient> { 7 private RedisClientConfig redisClientConfig = new RedisClientConfig(); 8 9 public RedisClient getObject() throws Exception { 10 if (StringUtils.isNotBlank(this.redisClientConfig.getIpConfString())) { 11 return new RedisClient(this.redisClientConfig); 12 } 13 throw new RedisInitializerException('RedisClient init parameter masterConfString is empty,please check spring config file!'); 14 } 15 16 public Class<?> getObjectType() { 17 return RedisClient.class; 18 } 19 20 public boolean isSingleton() { 21 return true; 22 } 23 24 public void setIpConfString(String string) { 25 this.redisClientConfig.setIpConfString(string); 26 } 27 28 public void setMaxTotal(int maxTotal) { 29 this.redisClientConfig.setMaxTotal(maxTotal); 30 } 31 32 public void setMaxIdle(int maxIdle) { 33 this.redisClientConfig.setMaxIdle(maxIdle); 34 } 35 36 public void setMinIdle(int minIdle) { 37 this.redisClientConfig.setMinIdle(minIdle); 38 } 39 40 public void setTestOnBorrow(boolean flag) { 41 this.redisClientConfig.setTestOnBorrow(flag); 42 } 43 }

10.4 RedisClientConfig.java

1 package com.commons.redis; 2 3 import org.apache.commons.pool2.impl.GenericObjectPoolConfig; 4 5 /** 6 * 7 * @描述 : 配置redis的相关属性 8 * @创建时间: 2015年7月20日上午11:05:53 9 * 10 */ 11 public class RedisClientConfig { 12 private GenericObjectPoolConfig jedisPoolConfig = new GenericObjectPoolConfig(); 13 14 private String ipConfString; 15 16 /** 17 * 18 * @描述 : 单个应用中的链接池最大链接数 19 * @创建时间: 2015年7月20日上午11:11:10 20 * 21 * @param maxTotal 22 */ 23 public void setMaxTotal(int maxTotal) { 24 this.jedisPoolConfig.setMaxTotal(maxTotal); 25 } 26 27 /** 28 * @描述 :单个应用中的链接池最大空闲数 29 * @创建时间: 2015年7月20日上午11:11:28 30 * 31 * @param maxIdle 32 */ 33 34 35 public void setMaxIdle(int maxIdle) { 36 this.jedisPoolConfig.setMaxIdle(maxIdle); 37 } 38 39 40 /** 41 * @描述 : 单个应用中的链接池最大链接数 42 * @创建时间: 2015年7月20日上午11:11:43 43 * 44 * @param maxIdle 45 */ 46 public void setMinIdle(int minIdle) { 47 this.jedisPoolConfig.setMinIdle(minIdle); 48 } 49 50 /** 51 * @描述 : 设置在每一次取对象时测试ping 52 * @创建时间: 2015年7月20日上午11:11:58 53 * 54 * @param flag 55 */ 56 public void setTestOnBorrow(boolean flag) { 57 this.jedisPoolConfig.setTestOnBorrow(flag); 58 } 59 60 public GenericObjectPoolConfig getJedisPoolConfig() { 61 return this.jedisPoolConfig; 62 } 63 64 public String getIpConfString() { 65 return this.ipConfString; 66 } 67 68 public void setIpConfString(String ipConfString) { 69 this.ipConfString = ipConfString; 70 } 71 }

本站内容来源于网络,如有侵权请与我们联系,我们会及时删除,我们深感抱歉!
注:本站所有信息仅供学习参考!
本文地址为 https://v30.fanwenzhu.com/server/equal/11917.shtml

相关文章

风云图片

推荐阅读

返回负载均衡频道首页